package com.ruoyi.aitcommon.utils;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang3.StringUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * JSON文件中的参数处理
 */
public class JSONParamUtils {
//  变量正则表达式,举例:${parm},\\u4e00-\\u9fa5支持中文
//	支持格式:${demoService.getDate1},此为变量
//	支持格式:${$demoService.getDate1()},此为函数调用
//	支持格式:http://${demoService.getDate1}/webservice/${$demoService.getDate1()},此为含有变量的字符串
    private static Pattern pvar = Pattern.compile("\\$\\{(\\$){0,1}[^\\$\\{\\}]+?\\}");
//	不能使用下述表达式,因为"${aaa}-${bbb}"也会识别为整体变量
//	private static Pattern pvar = Pattern.compile("\\$\\{(\\$){0,1}.+?\\}");

    /**
     * 获取JSON中的所有变量,格式 ${}
     * @param jsonStr JSON内容
     * @param context 当前上下文
     * @return jsonStr内容里面的变量清单
     */
    public static List<String> getJSONParamsName(String jsonStr,Map<String,Object> context) throws Exception{
        List<String> retlist=new ArrayList<String>();
        if(containsParam(jsonStr)) {
//			字符串中包含变量,提取变量名
            Matcher m = pvar.matcher(jsonStr);
            while (m.find()) {
//				获取匹配到的字符串
                String name = m.group();
//				去掉${}
                retlist.add(getParam(name));
            }
        }
        return retlist;
    }

    /**
     * 获取字符串中的所有变量,格式 ${}
     * @param paramStr
     * @return
     */
    public static List<String> getStringParamsName(String paramStr) throws Exception{
        List<String> retlist=new ArrayList<>();
        if(containsParam(paramStr)) {
//			字符串中包含变量,提取变量名
            Matcher m = pvar.matcher(paramStr);
            while (m.find()) {
//				获取匹配到的字符串
                String name = m.group();
//				去掉${}
                retlist.add(name);
            }
        }
        return retlist;
    }

    /**
     * 判断是否完整变量,格式${parm}
     * @param parm
     * @return
     */
    public static boolean isParam(String parm) {
        if(StringUtils.isBlank(parm))
            return false;
        parm = parm.trim();
        Matcher matcher = pvar.matcher(parm);
//		是否完成匹配
        boolean flag=matcher.matches();
        return flag;
    }

    /**
     * 判断字符串中是否包含变量
     * 完整变量不算
     * 比如:"${parm}"不算,"aa${parm}bb"才算
     * @param val 字符串
     * @return
     */
    private static boolean containsParam(String val) {
        val = val.trim();

        Matcher matcher = pvar.matcher(val);
//		如果是完整匹配,代表是变量,不是包含
        if(matcher.matches())
            return false;

//		这里判断是否包含匹配
//		因为上面的matches()方法移动了指针,必须reset()
//		参考https://blog.csdn.net/ray2580/article/details/105473074
        matcher.reset();
        if(matcher.find())
            return true;
        else
            return false;
    }

    /**
     * 获取参数${parm}中的parm字符串
     * @param parm
     * @return
     */
    public static String getParam(String parm) throws Exception {
        String ret = parm;
        if (!isParam(ret)) {
            throw new Exception(String.format("参数[%s]格式错误", parm,parm));
        }
        ret = StringUtils.substring(ret, 2);
        ret = StringUtils.substring(ret, 0, ret.length() - 1);
        return ret.trim();
    }

    /**
     * 获取${}变量,对应的上下文中的值
     * @param parmstr 变量字符串
     * <pre>
     * 支持格式:
     * 	${sqldata.sql1}:变量
     * 	${$demoService.hello1()}:函数
     * 	"aaa":常量
     * </pre>
     *
     * @param context 上下文
     * @return
     * @throws Exception
     */
    private static Object getParamsValue(String parmstr,Map<String, Object> context) throws Exception {
        Object retobj = null;
        String parm = StringUtils.trimToEmpty(parmstr);
        if (JSONParamUtils.isParam(parm)) {
//    		如果是${}变量,从context中获取变量
            String key = getParam(parm);
            if(StrUtil.startWith(key, "$")) {
//                调用服务,获取变量
                String method=StrUtil.subWithLength(key, 1, key.length());
                retobj = BeanUtils.invokeMethod(method, context);
            }else {
//				从上下文中获取变量
                if (!MapUtils.containsPathObject(key, context))
                    throw new Exception("上下文中不存在参数:" + parm);
                retobj = MapUtils.getPathObject(key, context);
            }
        } else {
//    		当前参数就是变量
            retobj = parm;
        }
        return retobj;
    }

    /**
     * parm解析核心方法,解析参数parmstr,返回替换后的字符串
     * 如果是变量${},替换为上下文中的值
     * 如果是包含变量的字符串"aa${}bb",替换变量为上下文中的值.toString()
     * 如果是常量,直接返回
     * @param parmstr JSON字段的val
     * @param context 翻译上下文
     * @param Recursive 是否递归处理
     * @return 上下文中的变量或替换后的字符串
     */
    public static Object transParamsJSONValue(String parmstr
            , Map<String, Object> context,boolean Recursive)
            throws Exception {
        Object retobj = null;
        if(StrUtil.isBlank(parmstr)) return "";
        if (JSONParamUtils.isParam(parmstr)) {
//			变量${},从上下文取值
            retobj = getParamsValue(parmstr, context);
        } else if (containsParam(parmstr)) {
//			字符串中含有变量,从上下文取值后拼接
            StringBuffer sb = new StringBuffer();
            Matcher m = pvar.matcher(parmstr);
            while (m.find()) {
                String name = m.group();
                Object obj = getParamsValue(name, context);
                // 替换掉查找到的字符串
                m.appendReplacement(sb, obj.toString());
            }
            // 别忘了加上最后一点
            m.appendTail(sb);
            retobj = sb.toString();
        } else {
//			常量
            retobj = parmstr;
        }

//        如果变量翻译后,还是变量
        if(Recursive && ObjUtils.isNotBlank(retobj)){
            if(retobj instanceof JSONObject||retobj instanceof JSONArray){
//                翻译后,是对象,针对对象继续翻译
                retobj=transParamsJSON(retobj,context);
            }
            else if(retobj instanceof String){
                if(JSONParamUtils.isParam(retobj.toString())
                        ||JSONParamUtils.containsParam(retobj.toString()))
//                变量递归引用
                retobj=getParamsValue(retobj.toString(), context);
            }
        }
        return retobj;
    }

    /**
     * 替换JSON中的变量
     * 支持类型:字符串,集合,对象
     * @param parms JSON对象
     * @param context 上下文
     * @return 替换变量后的JSON
     */
    public static Object transParamsJSON(Object parms, Map<String, Object> context)
            throws Exception {
//		递归循环flowparms中的所有key
        Object retObj=JSONUtils.pathJSON(parms, (key,val) -> {
            if (val instanceof String) {
//				处理parms中的常量和变量${}
                Object oval = transParamsJSONValue(val.toString(), context,true);
//				返回参数翻译后的key,value数组
                return new Object[] {key,oval};
            }
            else {
//                直接返回val
                return new Object[] {key,val};
            }
        });
        return retObj;
    }
}
